package com.lucifer.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.lucifer.entity.*;
import com.lucifer.enums.ParsePdmType;
import org.dom4j.*;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import static com.lucifer.enums.ParsePdmType.PDM_FROM_FILE;
import static com.lucifer.enums.ParsePdmType.PDM_FROM_PACKAGE;

/**
 * 功能描述:
 * <p>
 * Created by Mr.wang on 2017/6/6 16:32.
 */
public class ParsePDM2JSON {
    public static void parsePdm2List(String pdmPath) {
        System.out.println("开始解析");
        try {
            SAXReader saxReader = new SAXReader();
            //1.读取XML文件，获得document对象
            Document document = saxReader.read(new File(pdmPath));
            Node node = document.selectSingleNode(ParsePdmType.PDM_MODEL.toString());
            System.out.println("解析方式起始位置：" + ParsePdmType.PDM_MODEL.toString());
            parsePdm(node);
        } catch (DocumentException e) {
            e.printStackTrace();
            System.out.println("报错啦，小兄弟：" + e.getMessage().toString());
        }
    }


    /**
     * 开始解析
     *
     * @param node 开始的节点
     */
    private static void parsePdm(Node node) {
        PdmModel pdmModel = new PdmModel();
//        List<Node> fileNodes = node.selectNodes(PDM_FROM_FILE.toString());
//        List<PdmFile> fileList = parseWithFile(fileNodes);
//        pdmModel.setPdmFiles(fileList);
        List<Node> packageNodes = node.selectNodes(PDM_FROM_PACKAGE.toString());
        List<PdmPackage> packageList = parseWithPackage(packageNodes);
        pdmModel.setPdmPackages(packageList);
        System.out.println("PdmModel JSON:" + JSON.toJSONString(pdmModel, SerializerFeature.WriteNullStringAsEmpty));
    }

    /**
     * 解析 package
     *
     * @return
     */
    private static List<PdmPackage> parseWithPackage(List<Node> nodes) {
        List<PdmPackage> packages = new ArrayList<PdmPackage>();
        String code, name, creationDate, creator, modificationDate, modifier;
        for (Node node : nodes) {
            PdmTable pdmTable = new PdmTable();
            PdmPackage pdmPackage = new PdmPackage();
            Node codeNode = node.selectSingleNode("a:Code");
            Node nameNode = node.selectSingleNode("a:Name");
            Node creationDateNode = node.selectSingleNode("a:CreationDate");
            Node creatorNode = node.selectSingleNode("a:Creator");
            Node modificationDateNode = node.selectSingleNode("a:ModificationDate");
            Node modifierNode = node.selectSingleNode("a:Modifier");
            List<Node> tablesNodes = node.selectNodes("c:Tables/o:Table");
            code = codeNode != null ? codeNode.getText() : "";
            name = nameNode != null ? nameNode.getText() : "";
            creationDate = creationDateNode != null ? DateFormatter.stampToDate(creationDateNode.getText()) : "";
            creator = creatorNode != null ? creatorNode.getText() : "";
            modificationDate = modificationDateNode != null ? DateFormatter.stampToDate(modificationDateNode.getText()) : "";
            modifier = modifierNode != null ? modifierNode.getText() : "";
            pdmTable.setCode(code);
            pdmTable.setName(name);
            pdmTable.setCreationDate(creationDate);
            pdmTable.setCreator(creator);
            pdmTable.setModificationDate(modificationDate);
            pdmTable.setModifier(modifier);
            List<PdmTable> pdmTables = parseWithTable(tablesNodes);
            pdmPackage.setPdmTables(pdmTables);
            packages.add(pdmPackage);
        }
        return packages;
    }


    /**
     * 解析 PdmFile
     *
     * @return
     */
    private static List<PdmFile> parseWithFile(List<Node> filesNodes) {
        List<PdmFile> pdmFiles = new ArrayList<PdmFile>();
        String code, name, creationDate, creator, modificationDate, modifier, content;
        for (Node node : filesNodes) {
            PdmFile pdmFile = new PdmFile();
            Node codeNode = node.selectSingleNode("a:Code");
            Node nameNode = node.selectSingleNode("a:Name");
            Node creationDateNode = node.selectSingleNode("a:CreationDate");
            Node creatorNode = node.selectSingleNode("a:Creator");
            Node modificationDateNode = node.selectSingleNode("a:ModificationDate");
            Node modifierNode = node.selectSingleNode("a:Modifier");
            Node contentNode = node.selectSingleNode("a:FileObject.Content");
            code = codeNode != null ? codeNode.getText() : "";
            name = nameNode != null ? nameNode.getText() : "";
            creationDate = creationDateNode != null ? DateFormatter.stampToDate(creationDateNode.getText()) : "";
            creator = creatorNode != null ? creatorNode.getText() : "";
            modificationDate = modificationDateNode != null ? DateFormatter.stampToDate(modificationDateNode.getText()) : "";
            modifier = modifierNode != null ? modifierNode.getText() : "";
            content = contentNode != null ? contentNode.getText() : "";
            pdmFile.setCode(code);
            pdmFile.setName(name);
            pdmFile.setCreationDate(creationDate);
            pdmFile.setCreator(creator);
            pdmFile.setModificationDate(modificationDate);
            pdmFile.setModifier(modifier);
            pdmFile.setContent(content);
            pdmFiles.add(pdmFile);
        }
        return pdmFiles;
    }


    /**
     * 解析 table
     *
     * @param nodes
     * @return
     */
    private static List<PdmTable> parseWithTable(List<Node> nodes) {
        List<PdmTable> pdmTables = new ArrayList<PdmTable>();
        String code, name, creationDate, creator, modificationDate, modifier, comment;
        for (Node node : nodes) {
            PdmTable pdmTable = new PdmTable();
            Node codeNode = node.selectSingleNode("a:Code");
            Node nameNode = node.selectSingleNode("a:Name");
            Node creationDateNode = node.selectSingleNode("a:CreationDate");
            Node creatorNode = node.selectSingleNode("a:Creator");
            Node modificationDateNode = node.selectSingleNode("a:ModificationDate");
            Node modifierNode = node.selectSingleNode("a:Modifier");
            Node commentNode = node.selectSingleNode("a:Comment");
            Node primaryKeyNode = node.selectSingleNode("c:PrimaryKey/o:Key");//主键
            Node keysNode = node.selectSingleNode("c:Keys/o:Key");//键
            List<Node> columnNodes = node.selectNodes("c:Columns/o:Column");//列
            code = codeNode != null ? codeNode.getText() : "";
            name = nameNode != null ? nameNode.getText() : "";
            creationDate = creationDateNode != null ? DateFormatter.stampToDate(creationDateNode.getText()) : "";
            creator = creatorNode != null ? creatorNode.getText() : "";
            modificationDate = modificationDateNode != null ? DateFormatter.stampToDate(modificationDateNode.getText()) : "";
            modifier = modifierNode != null ? modifierNode.getText() : "";
            comment = commentNode != null ? commentNode.getText() : "";
            pdmTable.setCode(code);
            pdmTable.setName(name);
            pdmTable.setCreationDate(creationDate);
            pdmTable.setCreator(creator);
            pdmTable.setModificationDate(modificationDate);
            pdmTable.setModifier(modifier);
            pdmTable.setComment(comment);
            PdmPKey pdmPkKeyColumns = parseWithPkKeyColumns(primaryKeyNode);//主键
            PdmKeyColumn pdmKeyColumns = parseWithKeyColumns(keysNode);//键
            List<PdmColumn> pdmColumns = parseWithColumn(columnNodes, pdmKeyColumns, pdmPkKeyColumns);
            pdmTable.setPdmColumns(pdmColumns);//添加列信息
            pdmTables.add(pdmTable);
        }
        return pdmTables;
    }


    /**
     * @param columnsNodes   所有的列
     * @param pdmKeyColumn   所有的键
     * @param pdmPkKeyColumn 所有的主键
     * @return
     */
    private static List<PdmColumn> parseWithColumn(List<Node> columnsNodes, PdmKeyColumn pdmKeyColumn, PdmPKey pdmPkKeyColumn) {
//        key的ref对应column的Id， 再通过primary key 的 ref和 key的id
        List<PdmColumn> pdmColumns = new ArrayList<>();
        for (Node node : columnsNodes) {
            PdmColumn pdmColumn = new PdmColumn();
            String id, code, name, comment, dataType, length, mandatory;
            id = node.valueOf("@Id");
            Node nameNode = node.selectSingleNode("a:Name");
            Node codeNode = node.selectSingleNode("a:Code");
            Node commentNode = node.selectSingleNode("a:Comment");
            Node dataTypeNode = node.selectSingleNode("a:DataType");
            Node lengthNode = node.selectSingleNode("a:Length");
            Node mandatoryNode = node.selectSingleNode("a:Column.Mandatory");
            code = codeNode != null ? codeNode.getText() : "";
            comment = commentNode != null ? commentNode.getText() : "";
            name = nameNode != null ? nameNode.getText() : "";
            dataType = dataTypeNode != null ? dataTypeNode.getText() : "";
            length = lengthNode != null ? lengthNode.getText() : "";
            mandatory = mandatoryNode != null ? mandatoryNode.getText() : "0";//是否可为空？
            pdmColumn.setId(id);
            pdmColumn.setCode(code);
            pdmColumn.setName(name);
            pdmColumn.setComment(comment);
            pdmColumn.setDataType(dataType);
            pdmColumn.setLength(length);
            pdmColumn.setMandatory(mandatory);
            pdmColumn.setIsPk("0");
            for (String ref : pdmKeyColumn.getRef()) { //ref 是键key的
                if (ref.equals(pdmColumn.getId()) && pdmPkKeyColumn.getRef().equals(pdmKeyColumn.getId())) {//确定 column和key的联系
                    pdmColumn.setIsPk("1");//如果该列的id和本表下的主键的ref相同  则该列为主键
                    continue;
                }
            }
            pdmColumns.add(pdmColumn);
//            System.out.println("pdmColumn:[" + id + "]" + pdmColumn.toString());
        }
        return pdmColumns;
    }


    /**
     * 解析 PrimaryKeyColumns
     *
     * @return
     */
    private static PdmPKey parseWithPkKeyColumns(Node columnsNode) {
        PdmPKey pdmPKeyColumn = new PdmPKey();
        String id, ref;
        ref = columnsNode.valueOf("@Ref");
        pdmPKeyColumn.setRef(ref);
//        System.out.println("pdmPKeyColumns:[" + ref + "]" + pdmPKeyColumn.toString());
        return pdmPKeyColumn;
    }

    /**
     * 解析 KeyColumns
     *
     * @return
     */
    private static PdmKeyColumn parseWithKeyColumns(Node columnsNode) {
        PdmKeyColumn pdmKeyColumn = new PdmKeyColumn();
        String id, ref;
        id = columnsNode.valueOf("@Id");
        List<String> refList = new ArrayList<>();
        List<Node> keyNodes = columnsNode.selectNodes("c:Key.Columns/o:Column");//下级映射
        for (Node subNode : keyNodes) {
            ref = subNode.valueOf("@Ref");
            refList.add(ref);
        }
        pdmKeyColumn.setId(id);
        pdmKeyColumn.setRef(refList);
//        System.out.println("pdmKeyColumns:[" + id + "]" + pdmKeyColumn.toString());
        return pdmKeyColumn;
    }


    /**
     * 解析 Keys
     *
     * @return
     */
    private static List<PdmKey> parseWithKeys(List<Node> keysNodes) {
        List<PdmKey> pdmPdmKeys = new ArrayList<PdmKey>();
        String id, code, name, creationDate, creator, modificationDate, modifier;
        for (Node node : keysNodes) {
            PdmKey pdmPdmKey = new PdmKey();
            id = node.valueOf("@Id");
            Node codeNode = node.selectSingleNode("a:Code");
            Node nameNode = node.selectSingleNode("a:Name");
            Node creationDateNode = node.selectSingleNode("a:CreationDate");
            Node creatorNode = node.selectSingleNode("a:Creator");
            Node modificationDateNode = node.selectSingleNode("a:ModificationDate");
            Node modifierNode = node.selectSingleNode("a:Modifier");
            Node columnsNode = node.selectSingleNode("c:Key.Columns/o:Column");
            code = codeNode != null ? codeNode.getText() : "";
            name = nameNode != null ? nameNode.getText() : "";
            creationDate = creationDateNode != null ? DateFormatter.stampToDate(creationDateNode.getText()) : "";
            creator = creatorNode != null ? creatorNode.getText() : "";
            modificationDate = modificationDateNode != null ? DateFormatter.stampToDate(modificationDateNode.getText()) : "";
            modifier = modifierNode != null ? modifierNode.getText() : "";
            pdmPdmKey.setCode(code);
            pdmPdmKey.setName(name);
            pdmPdmKey.setCreationDate(creationDate);
            pdmPdmKey.setCreator(creator);
            pdmPdmKey.setModificationDate(modificationDate);
            pdmPdmKey.setModifier(modifier);
            PdmKeyColumn pdmKeyColumns = parseWithKeyColumns(columnsNode);
            pdmPdmKey.setPdmKeyColumn(pdmKeyColumns);
            pdmPdmKeys.add(pdmPdmKey);
        }
        return pdmPdmKeys;
    }


    /**
     * 解析成泛型类
     *
     * @param nodes
     * @return
     */
    private static List<PdmTable> parseWithCommon(List<Node> nodes) {
        List<PdmTable> pdmTables = new ArrayList<PdmTable>();
        String code, name, creationDate, creator, modificationDate, modifier, comment;
        String id;
        List<PdmColumn> pdmColumns;
        for (Node node : nodes) {
            PdmTable pdmTable = new PdmTable();
            id = node.valueOf("@Id");
            Node codeNode = node.selectSingleNode("a:Code");
            Node nameNode = node.selectSingleNode("a:Name");
            Node creationDateNode = node.selectSingleNode("a:CreationDate");
            Node creatorNode = node.selectSingleNode("a:Creator");
            Node modificationDateNode = node.selectSingleNode("a:ModificationDate");
            Node modifierNode = node.selectSingleNode("a:Modifier");
            Node commentNode = node.selectSingleNode("a:Comment");
            List<Node> columnsNodes = node.selectNodes("c:Columns/o:Column");
            Node primaryKeyNode = node.selectSingleNode("c:PrimaryKey/o:Key");
            Node keysNode = node.selectSingleNode("c:Keys/o:Key");
            code = codeNode != null ? codeNode.getText() : "";
            name = nameNode != null ? nameNode.getText() : "";
            creationDate = creationDateNode != null ? DateFormatter.stampToDate(creationDateNode.getText()) : "";
            creator = creatorNode != null ? creatorNode.getText() : "";
            modificationDate = modificationDateNode != null ? DateFormatter.stampToDate(modificationDateNode.getText()) : "";
            modifier = modifierNode != null ? modifierNode.getText() : "";
            comment = commentNode != null ? commentNode.getText() : "";
            pdmTable.setId(id);
            pdmTable.setCode(code);
            pdmTable.setName(name);
            pdmTable.setCreationDate(creationDate);
            pdmTable.setCreator(creator);
            pdmTable.setModificationDate(modificationDate);
            pdmTable.setModifier(modifier);
            pdmTable.setComment(comment);
            PdmPKey pdmPkKeyColumn = parseWithPkKeyColumns(keysNode);//主键
            PdmKeyColumn pdmKeyColumn = parseWithKeyColumns(primaryKeyNode);
            pdmColumns = parseWithColumn(columnsNodes, pdmKeyColumn, pdmPkKeyColumn);
//            pdmColumns = parseWithColumn(columnsNodes, pdmPkKeyColumns);
            pdmTable.setPdmColumns(pdmColumns);
            pdmTables.add(pdmTable);
//            System.out.println("pdmTable:[" + id + "]" + pdmTable.toString());
        }
        return pdmTables;
    }

    /**
     * 遍历当前节点元素下面的所有(元素的)子节点
     *
     * @param node
     */
    public static void listNodes(Element node) {
        System.out.println("当前节点的名称：：" + node.getName());
        // 获取当前节点的所有属性节点
        List<Attribute> list = node.attributes();
        // 遍历属性节点
        for (Attribute attr : list) {
            System.out.println(attr.getText() + "-----" + attr.getName() + "---" + attr.getValue());
        }

        if (!(node.getTextTrim().equals(""))) {
            System.out.println("文本内容：：：：" + node.getText());
        }

        // 当前节点下面子节点迭代器
        Iterator<Element> it = node.elementIterator();
        // 遍历
        while (it.hasNext()) {
            // 获取某个子节点对象
            Element e = it.next();
            // 对子节点进行遍历
            listNodes(e);
        }
    }

}
